package com.jt.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.sound.midi.Soundbank;
import javax.xml.transform.Result;
import java.lang.reflect.Array;
import java.util.Arrays;

@Component  //将给类交给Spring容器管理！！
@Aspect     //标识该类是一个切面
@Order(2)   //按照顺序第二个执行
public class SpringAOP {

    /**
     * 知识回顾：   AOP利用动态代理扩展目标方法。
     * 公式：      切面 = 切入点表达式 + 通知方法、
     * 切入点表达式：如果目标对象满足切入点表达式的判断(if)，
     *            则spring自欧东为其创建代理对象
     * 通知方法：   对目标方法进行拓展的封装方法
     * 目标对象的bean的ID：userServiceImpl
     * 切入点表达式：
     *       1.bean("bean的ID")
     * AOP规则：如果目标对象满足切入点表达式，则执行通知方法
     */

    //切入点表达式
    //根据bean的ID拦截指定的对象
//    @Pointcut("bean(userServiceImpl)")
    //
    //只拦截UserServiceImpl类
//    @Pointcut("within(com.jt.service.UserServiceImpl)")
    //拦截com.jt.service包下的一级类
//    @Pointcut("within(com.jt.service.*)")
    //拦截com.jt.service包下的所有包所有类
//    @Pointcut("within(com.jt.service..*)")
    //拦截cpm.任意包.service下所有包下的所有类
//    @Pointcut("within(com.*.service..*)")
//    @Pointcut("execution(* com.jt.service.UserServiceImpl.addUser())")
    //标记注解
    @Pointcut("@annotation(com.jt.anno.Zy)")
    public void pointcut(){

    }
    //1.前置通知：在目标方法执行之前执行
    @Before("pointcut()")
    public void before(JoinPoint joinPoint){//连接点：获取方法中的数据
        //获取类型
        Class targetClass = joinPoint.getTarget().getClass();
        //获取方法名称
        String name1 = joinPoint.getSignature().getName();
        String name2 = joinPoint.getSignature().getDeclaringTypeName();
        Object[] objs = joinPoint.getArgs();
        System.out.println("我是前置通知");
        System.out.println("类型："+targetClass);
        System.out.println("方法名称："+name1);
        System.out.println("类的名称："+name2);
        System.out.println("方法中携带的参数："+ Arrays.toString(objs));
    }

    //2.后置通知：在目标方法执行之后执行
    //通过returning = "result"属性，获取目标方法的返回值，当做参数传递给result
    @AfterReturning(value = "pointcut()",returning = "result")
    public void afterReturn(Object result){
        System.out.println("我是后置通知！！！");
        System.out.println("用户的返回值为："+result);
    }

    //3.异常通知：在目标方法执行报错时，执行该通知
    @AfterThrowing(value = "pointcut()",throwing = "exception")
    public void afterThrowing(Exception exception){
        System.out.println("我是异常通知！！");
        System.out.println("获取异常信息"+exception.getMessage());
    }

    //4.最终通知：目标方法之后都要执行的通知
    @After("pointcut()")
    public void after(){
        System.out.println("最终通知都要执行");
    }

    //5.重点掌握  环绕通知:在目标方法执行前后都要执行，控制目标方法
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕通知A执行前！！！");
        //底层调用动态代理的invoke方法，执行目标方法
        Object result = joinPoint.proceed();
        System.out.println("环绕通知A执行后！！！");
        return result;
    }


}
